import json
import os
import socket
import threading
import tkinter as tk
from datetime import datetime
from tkinter import scrolledtext, filedialog, messagebox

import ttkbootstrap as ttk
from ttkbootstrap.constants import *

from app.util.annotation_util import annotate, ClassInfo
from app.view.base_view import View


@annotate(ClassInfo(name="FtUdpConfig", category="ft_tool"))
class FtUdpConfigView(View):

    def __init__(self, parent, controller):
        super().__init__(parent, controller)
        # UDP相关变量
        self.udp_socket = None
        self.is_running = False
        self.receive_thread = None
        self.remote_addresses = []  # 存储远程地址列表

        # 创建主框架
        self.main_frame = ttk.Frame(self, padding=10)
        self.main_frame.pack(fill=BOTH, expand=True)

        # 创建界面组件
        self._create_widgets()

        # 加载保存的地址
        self.load_saved_addresses()

    def _create_widgets(self):
        # 顶部配置区域
        config_frame = ttk.LabelFrame(self.main_frame, text="配置", padding=10)
        config_frame.pack(fill=X, pady=(0, 10))

        # 本地端口配置
        ttk.Label(config_frame, text="本地端口:").grid(row=0, column=0, padx=5, pady=5, sticky=W)
        self.local_port_var = ttk.StringVar(value="5000")
        ttk.Entry(config_frame, textvariable=self.local_port_var, width=10).grid(row=0, column=1, padx=5, pady=5)

        # 服务控制按钮
        self.start_stop_btn = ttk.Button(config_frame, text="启动服务", command=self.toggle_service)
        self.start_stop_btn.grid(row=0, column=2, padx=5, pady=5)

        # 远程地址配置
        ttk.Label(config_frame, text="远程IP:").grid(row=0, column=3, padx=5, pady=5, sticky=W)
        self.remote_ip_var = ttk.StringVar(value="127.0.0.1")
        ttk.Entry(config_frame, textvariable=self.remote_ip_var, width=15).grid(row=0, column=4, padx=5, pady=5)

        ttk.Label(config_frame, text="远程端口:").grid(row=0, column=5, padx=5, pady=5, sticky=W)
        self.remote_port_var = ttk.StringVar(value="5000")
        ttk.Entry(config_frame, textvariable=self.remote_port_var, width=10).grid(row=0, column=6, padx=5, pady=5)

        # 添加地址按钮
        ttk.Button(config_frame, text="添加地址", command=self.add_remote_address).grid(row=0, column=7, padx=5, pady=5)

        # 日志操作按钮
        ttk.Button(config_frame, text="清空日志", command=self.clear_log).grid(row=0, column=8, padx=5, pady=5)
        ttk.Button(config_frame, text="保存日志", command=self.save_log).grid(row=0, column=9, padx=5, pady=5)

        # 中间区域 - 分为左右两部分
        mid_frame = ttk.Frame(self.main_frame)
        mid_frame.pack(fill=BOTH, expand=True, pady=(0, 10))

        # 左侧 - 地址列表
        addr_frame = ttk.LabelFrame(mid_frame, text="远程地址列表", padding=10)
        addr_frame.pack(side=LEFT, fill=BOTH, expand=True, padx=(0, 10))

        # 地址列表操作按钮 - 现在位于列表顶部
        addr_btn_frame = ttk.Frame(addr_frame)
        addr_btn_frame.pack(fill=X, pady=(0, 5))  # 仅在下方添加间距

        ttk.Button(addr_btn_frame, text="删除选中", command=self.remove_selected_addresses).pack(side=LEFT, padx=5)
        ttk.Button(addr_btn_frame, text="清空列表", command=self.clear_address_list).pack(side=LEFT, padx=5)

        # 地址列表
        self.address_listbox = tk.Listbox(addr_frame, selectmode=tk.EXTENDED, height=10)
        self.address_listbox.pack(side=LEFT, fill=BOTH, expand=True)

        scrollbar = ttk.Scrollbar(addr_frame, orient=VERTICAL, command=self.address_listbox.yview)
        scrollbar.pack(side=RIGHT, fill=Y)
        self.address_listbox.config(yscrollcommand=scrollbar.set)

        # 右侧 - 发送数据区域
        send_frame = ttk.LabelFrame(mid_frame, text="发送数据", padding=10)
        send_frame.pack(side=RIGHT, fill=BOTH, expand=True, padx=(10, 0))

        # 发送选项
        send_options_frame = ttk.Frame(send_frame)
        send_options_frame.pack(fill=X, pady=(0, 5))

        self.hex_send_var = ttk.BooleanVar(value=False)
        ttk.Checkbutton(send_options_frame, text="Hex格式发送", variable=self.hex_send_var).pack(side=LEFT, padx=5)

        self.newline_var = ttk.BooleanVar(value=False)
        ttk.Checkbutton(send_options_frame, text="添加换行", variable=self.newline_var).pack(side=LEFT, padx=5)

        self.broadcast_var = ttk.BooleanVar(value=False)
        ttk.Checkbutton(send_options_frame, text="广播", variable=self.broadcast_var).pack(side=LEFT, padx=5)

        self.multicast_var = ttk.BooleanVar(value=False)
        ttk.Checkbutton(send_options_frame, text="多播", variable=self.multicast_var).pack(side=LEFT, padx=5)

        # 发送数据文本框
        self.send_text = scrolledtext.ScrolledText(send_frame, height=8)
        self.send_text.pack(fill=BOTH, expand=True, pady=(5, 5))

        # 发送按钮
        ttk.Button(send_frame, text="发送数据", command=self.send_data, bootstyle=SUCCESS).pack(fill=X, pady=5)

        # 底部日志区域
        log_frame = ttk.LabelFrame(self.main_frame, text="日志", padding=10)
        log_frame.pack(fill=BOTH, expand=True)

        # 日志文本框
        self.log_text = scrolledtext.ScrolledText(log_frame, state=DISABLED, height=15)
        self.log_text.pack(fill=BOTH, expand=True, pady=(0, 5))

    def toggle_service(self):
        """启动或停止UDP服务"""
        if not self.is_running:
            try:
                local_port = int(self.local_port_var.get())
                self.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

                # 允许广播
                self.udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

                self.udp_socket.bind(('0.0.0.0', local_port))
                self.is_running = True
                self.start_stop_btn.config(text="停止服务", bootstyle=DANGER)
                self.log(f"服务已启动，监听本地端口: {local_port}")

                # 启动接收线程
                self.receive_thread = threading.Thread(target=self.receive_data, daemon=True)
                self.receive_thread.start()
            except Exception as e:
                self.log(f"启动服务失败: {str(e)}", "error")
                self.udp_socket = None
                self.is_running = False
        else:
            self.is_running = False
            if self.udp_socket:
                self.udp_socket.close()
                self.udp_socket = None
            self.start_stop_btn.config(text="启动服务", bootstyle=DEFAULT)
            self.log("服务已停止")

    def receive_data(self):
        """接收UDP数据的线程函数"""
        while self.is_running and self.udp_socket:
            try:
                data, addr = self.udp_socket.recvfrom(4096)
                timestamp = datetime.now().strftime("%H:%M:%S")
                self.log(f"[{timestamp}] 收到来自 {addr[0]}:{addr[1]} 的数据:")

                # 同时显示原始数据和十六进制格式
                try:
                    str_data = data.decode('utf-8', errors='replace')
                    self.log(f"Text: {str_data}")
                except:
                    pass

                hex_data = ' '.join(f'{b:02x}' for b in data)
                self.log(f"HEX : {hex_data}")

            except Exception as e:
                if self.is_running:  # 如果不是主动停止服务，才记录错误
                    self.log(f"接收数据错误: {str(e)}", "error")
                break

    def add_remote_address(self):
        """添加远程地址到列表"""
        try:
            ip = self.remote_ip_var.get()
            port = int(self.remote_port_var.get())

            if not ip or port < 1 or port > 65535:
                messagebox.showerror("错误", "请输入有效的IP和端口")
                return

            address = (ip, port)
            if address not in self.remote_addresses:
                self.remote_addresses.append(address)
                self.address_listbox.insert(END, f"{ip}:{port}")
                self.log(f"已添加远程地址: {ip}:{port}")
                self.save_addresses()
            else:
                messagebox.showinfo("提示", "该地址已在列表中")
        except ValueError:
            messagebox.showerror("错误", "端口必须是数字")

    def remove_selected_addresses(self):
        """删除选中的地址"""
        selected_indices = sorted(self.address_listbox.curselection(), reverse=True)
        if not selected_indices:
            messagebox.showinfo("提示", "请先选择要删除的地址")
            return

        for i in selected_indices:
            del self.remote_addresses[i]
            self.address_listbox.delete(i)

        self.log(f"已删除 {len(selected_indices)} 个地址")
        self.save_addresses()

    def clear_address_list(self):
        """清空地址列表"""
        if messagebox.askyesno("确认", "确定要清空所有地址吗?"):
            self.remote_addresses.clear()
            self.address_listbox.delete(0, END)
            self.log("已清空地址列表")
            self.save_addresses()

    def send_data(self):
        """发送数据到选中的地址"""
        if not self.is_running or not self.udp_socket:
            messagebox.showwarning("警告", "请先启动服务")
            return

        if not self.remote_addresses and not self.broadcast_var.get():
            messagebox.showwarning("警告", "请先添加远程地址")
            return

        # 获取要发送的数据
        data = self.send_text.get("1.0", END).rstrip('\n')
        if not data:
            messagebox.showwarning("警告", "请输入要发送的数据")
            return

        # 处理Hex格式
        if self.hex_send_var.get():
            try:
                # 移除所有空格
                data = data.replace(' ', '')
                # 转换为字节
                data_bytes = bytes.fromhex(data)
            except ValueError as e:
                messagebox.showerror("错误", f"无效的Hex格式: {str(e)}")
                return
        else:
            # 处理换行
            if self.newline_var.get():
                data += '\n'
            data_bytes = data.encode('utf-8')

        # 处理广播
        if self.broadcast_var.get():
            # 使用255.255.255.255作为广播地址
            addresses_to_send = [("255.255.255.255", int(self.remote_port_var.get()))]
        # 处理多播
        elif self.multicast_var.get():
            # 设置多播TTL
            self.udp_socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
            addresses_to_send = self.remote_addresses
        else:
            # 获取选中的地址，如果没有选中则发送到所有地址
            selected_indices = self.address_listbox.curselection()
            if selected_indices:
                addresses_to_send = [self.remote_addresses[i] for i in selected_indices]
            else:
                addresses_to_send = self.remote_addresses

        # 发送数据
        success_count = 0
        for addr in addresses_to_send:
            try:
                self.udp_socket.sendto(data_bytes, addr)
                success_count += 1
            except Exception as e:
                self.log(f"发送到 {addr[0]}:{addr[1]} 失败: {str(e)}", "error")

        timestamp = datetime.now().strftime("%H:%M:%S")
        self.log(f"[{timestamp}] 已发送数据到 {success_count}/{len(addresses_to_send)} 个地址")

        # 显示发送的数据
        self.log(f"  发送的数据:")
        if self.hex_send_var.get():
            self.log(f"HEX : {data}")
        else:
            self.log(f"Text: {data}")

    def log(self, message, level="info"):
        """添加日志信息"""
        self.log_text.config(state=NORMAL)

        if level == "error":
            self.log_text.insert(END, f"[错误] {message}\n", "error")
        else:
            self.log_text.insert(END, f"{message}\n")

        self.log_text.tag_config("error", foreground="red")
        self.log_text.config(state=DISABLED)
        self.log_text.see(END)  # 滚动到最后

    def clear_log(self):
        """清空日志"""
        self.log_text.config(state=NORMAL)
        self.log_text.delete("1.0", END)
        self.log_text.config(state=DISABLED)
        self.log("日志已清空")

    def save_log(self):
        """保存日志到文件"""
        log_content = self.log_text.get("1.0", END)
        if not log_content.strip():
            messagebox.showinfo("提示", "日志为空，无需保存")
            return

        file_path = filedialog.asksaveasfilename(
            defaultextension=".txt",
            filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")],
            title="保存日志"
        )

        if file_path:
            try:
                with open(file_path, "w", encoding="utf-8") as f:
                    f.write(log_content)
                self.log(f"日志已保存到: {file_path}")
            except Exception as e:
                self.log(f"保存日志失败: {str(e)}", "error")

    def save_addresses(self):
        """保存地址列表到文件"""
        try:
            data = [{"ip": ip, "port": port} for ip, port in self.remote_addresses]
            with open("./config/udp_addresses.json", "w", encoding="utf-8") as f:
                json.dump(data, f, ensure_ascii=False, indent=2)
        except Exception as e:
            self.log(f"保存地址列表失败: {str(e)}", "error")

    def load_saved_addresses(self):
        """从文件加载地址列表"""
        try:
            if os.path.exists("./config/udp_addresses.json"):
                with open("./config/udp_addresses.json", "r", encoding="utf-8") as f:
                    data = json.load(f)
                    self.remote_addresses = [(item["ip"], item["port"]) for item in data]
                    for ip, port in self.remote_addresses:
                        self.address_listbox.insert(END, f"{ip}:{port}")
                self.log(f"已加载 {len(self.remote_addresses)} 个保存的地址")
        except Exception as e:
            self.log(f"加载地址列表失败: {str(e)}", "error")

    def on_closing(self):
        """窗口关闭时的处理"""
        if self.is_running:
            self.toggle_service()
        self.destroy()

    def create_widgets(self):
        pass
